Skip to content

[libc++] Fix diagnostic for <stdatomic.h> before C++23 #83351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 4, 2024

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Feb 28, 2024

We normally try to issue a reasonable diagnostic when mixing <stdatomic.h> and before C++23. However, after granularizing the header, the check and the #error message was moved to after the point where mixing both causes problems. When mixing both headers, we would hence get the diagnostic burried under a pile of previous diagnostics in e.g. __atomic/kill_dependency.h.

This patch moves the check earlier to restore the intended behavior. It also switches from #ifdef kill_dependency to an explicit check of the inclusion of the header and the Standard version, which seems to be more reliable than checking whether a macro is defined.

@ldionne ldionne requested a review from a team as a code owner February 28, 2024 22:29
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Feb 28, 2024
@llvmbot
Copy link
Member

llvmbot commented Feb 28, 2024

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

We normally try to issue a reasonable diagnostic when mixing <stdatomic.h> and <atomic> before C++23. However, after granularizing the <atomic> header, the check and the #error message was moved to after the point where mixing both causes problems. When mixing both headers, we would hence get the diagnostic burried under a pile of previous diagnostics in e.g. __atomic/kill_dependency.h.

This patch moves the check earlier to restore the intended behavior. It also switches from #ifdef kill_dependency to an explicit check of the inclusion of the header and the Standard version, which seems to be more reliable than checking whether a macro is defined.


Full diff: https://github.com/llvm/llvm-project/pull/83351.diff

1 Files Affected:

  • (modified) libcxx/include/atomic (+4-4)
diff --git a/libcxx/include/atomic b/libcxx/include/atomic
index 2e8f5b521a55eb..ab6fc566aabc02 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -587,6 +587,10 @@ template <class T>
 
 */
 
+#if _LIBCPP_STD_VER < 23 && defined(_LIBCPP_STDATOMIC_H)
+#  error <atomic> is incompatible with <stdatomic.h> before C++23. Please compile with -std=c++23.
+#endif
+
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__atomic/aliases.h>
 #include <__atomic/atomic.h>
@@ -613,10 +617,6 @@ template <class T>
 #  error <atomic> is not implemented
 #endif
 
-#ifdef kill_dependency
-#  error <atomic> is incompatible with <stdatomic.h> before C++23. Please compile with -std=c++23.
-#endif
-
 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
 #  include <cmath>
 #  include <compare>

We normally try to issue a reasonable diagnostic when mixing <stdatomic.h>
and <atomic> before C++23. However, after granularizing the <atomic> header,
the check and the #error message was moved to *after* the point where mixing
both causes problems. When mixing both headers, we would hence get the
diagnostic burried under a pile of previous diagnostics in e.g.
__atomic/kill_dependency.h.

This patch moves the check earlier to restore the intended behavior. It
also switches from `#ifdef kill_dependency` to an explicit check of the
inclusion of the header and the Standard version, which seems to be more
reliable than checking whether a macro is defined.
@ldionne ldionne force-pushed the review/stdatomic-diagnostic branch from 7e73799 to b899632 Compare February 29, 2024 15:57
@mordante mordante self-assigned this Mar 3, 2024
Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks LGTM!

@ldionne ldionne merged commit 40081a4 into llvm:main Mar 4, 2024
@ldionne ldionne deleted the review/stdatomic-diagnostic branch March 4, 2024 23:24
@rprichard
Copy link
Contributor

I think this PR won't work with Android. Since 2014 (https://r.android.com/104366), Android has allowed including <stdatomic.h> or <atomic> in any order, even for language modes before C++23, and <stdatomic.h> delegates to <atomic>.

Maybe disable it for Bionic?

-#if _LIBCPP_STD_VER < 23 && defined(_LIBCPP_STDATOMIC_H)
+#if _LIBCPP_STD_VER < 23 && defined(_LIBCPP_STDATOMIC_H) && !defined(__BIONIC__)

I'm guessing libc++ doesn't have an Android-specific test verifying that stdatomic.h and atomic can both be used before C++23. I think I could add one.

@ldionne
Copy link
Member Author

ldionne commented Apr 2, 2024

I'm not sure how that ever worked since we did have an #error before, it just didn't provide a good diagnostic?

@rprichard
Copy link
Contributor

There are three stdatomic.h headers involved with Android:

  • libc++'s header (sysroot/usr/include/c++/v1 in the NDK package)
  • Clang's header (in the resource dir)
  • Bionic's header (sysroot/usr/include in the NDK package)

The previous libc++ #error was using the kill_dependency macro to detect whether stdatomic.h had been included. Clang's stdatomic.h is the only header of the three that defines the kill_dependency macro, and the Android LLVM build process overwrites Clang's stdatomic.h with the header from Bionic. A Python script copies the Bionic header into the resource directory:

https://android.googlesource.com/toolchain/llvm_android/+/9cb3f76f2ed7e5fc5fa14ee6e0b230433cecca3f/do_build.py#587

Both the Bionic and the libc++ stdatomic.h headers implement the C API using the C++ one, though the Bionic one does so for all language dialects. The libc++ header delegates to Bionic's stdatomic.h for C++20 and below, as long as _LIBCPP_COMPILER_CLANG_BASED is defined.

@rprichard
Copy link
Contributor

I wonder if libc++'s stdatomic.h to atomic delegation could be enabled for all language modes (maybe via a CMake setting / __config_site). Maybe then it'd be possible to delete Bionic's stdatomic.h and rely on the Clang/libc++ headers instead.

@rprichard
Copy link
Contributor

OTOH, Clang's stdatomic.h delegates to the system stdatomic.h, and maybe we'd want to keep that delegation for Bionic. I don't know why Android LLVM's build script is overwriting Clang's stdatomic.h, though. Maybe we needed it for host builds.

I do still wonder if it's possible to enable libc++'s stdatomic-to-atomic delegation for all language modes, though. That could simplify the situation on Android a lot if it worked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants